#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cerrno>
#include <cstring>
#include <string>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <thread>
#include "ThreadPool.hpp"
#include "Task.hpp"

void Usage(std::string proc)
{
    std::cout << "Usage\n\t" << proc << ":server_port" << std::endl;
}

void ServiceIO(int new_sock)
{
    while(true)
    {
        char buffer[1024];
        memset(buffer, 0, sizeof(buffer) - 1);
        ssize_t cnt = read(new_sock, buffer, sizeof(buffer)-1);
        if(cnt > 0)
        {
            buffer[cnt] = 0;
            std::cout << "client say# " << buffer << std::endl;
            std::string s;
            s += "server ";
            s += buffer;
            write(new_sock, s.c_str(), s.size());
        }
        else if(cnt == 0)
        {
            std::cout << "client quit..." << std::endl;
            break;
        }
        else
        {
            std::cerr << "read error" << std::endl;
            break;
        }
    }
}

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }

    uint16_t port = static_cast<uint16_t> (atoi(argv[1]));
    // 1.创建套接字, tcp
    // On success, a file descriptor for the new socket is returned. 
    // On error, -1 is returned, and errno is set appropriately.
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0)
    {
        std::cerr << "socket failed" << errno << std::endl;
        return 2;
    }
    // 2.bind 绑定
    // 头文件#include <arpa/inet.h> and #include <netinet/in.h>
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = INADDR_ANY;
    local.sin_port = htons(port);// 端口，在网络中是大端

    if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
        std::cerr << "bind failed" << errno << std::endl;
        return 3;
    }

    // 因为tcp是面向连接的, 在通信前，需要先建立连接，才能通信
    // 一定有人需要主动连接（客户端，需要服务），有人需要被动连接（服务器，提供服务）
    // 3.设置套接字是listen状态，，本质上是允许用户连接
    const int back_log = 5;
    if(listen(listen_sock, back_log) < 0)
    {
        std::cerr << "listen failed" << errno << std::endl;
    }

    //在Linux中父进程忽略子进程的SIGCHLD信号，子进程会自动退出释放资源
    // signal(SIGCHLD, SIG_IGN);
    // 4. 接受
    for(; ; )
    {
        struct sockaddr_in perr;
        socklen_t len = sizeof(perr);
        int new_sock = accept(listen_sock, (sockaddr*)&perr, &len);
        if(new_sock < 0)
            continue;
        u_int16_t client_port = ntohs(perr.sin_port);
        std::string client_ip = inet_ntoa(perr.sin_addr);
        std::cout << "get a new link->[" << client_ip << ":" << client_port << "]#" <<  new_sock << std::endl;

        // version4
        // 线程池或则进程池
        // 构建任务
        ns_task::Task t(new_sock);
        // 将任务push到线程池即可
        ns_task_queue::ThreadPool<ns_task::Task>::GetInstance()->PushTask(t);
        // version3
        // 创建线程或则进程无上西限
        // std::thread t1([new_sock] 
        // {
        //     ServiceIO(new_sock);
        //     close(new_sock);
        // }); 

        // t1.detach();
        // std::cout << "新线程分离成功!" << std::endl;

        // version 1,单进程没人使用
        //ServiceIO(new_sock);
        //version2， 多进程
        //pid_t pid = fork();
        // if(pid < 0)
        // {
        //     continue;
        // }
        // else if(pid == 0) // 曾经被父进程打开的fd，也会被继承
        // {
        //     // child
        //     close(listen_sock);
        //     if(fork() > 0)
        //     {
        //         exit(0); // 父进程终止,
        //     }
        //     else if(fork() == 0)
        //     {
        //         // 下面的是孙子进程, 父进程终止，孙子进程变为孤儿进程，由操作系统管理
        //         ServiceIO(new_sock);
        //         close(new_sock);
        //         exit(0);
        //     }
          
        // }

        // else
        // {
        //     // father 
        //     close(new_sock);
        //     waitpid(pid, 0, 0);
        // }
    }
    return 0;
}